﻿using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;

using Model;
using Model.NotarialFormEnot;

using NotarialFormStatusType = Model.NotarialForm.NotarialFormStatusType;

namespace NotarialFormMdbExport
{
    #region extensions

    public static class EnumerableExtensions
    {
        public static DataTable ToDataTable<T>(this IEnumerable<T> data)
        {
            return ToDataTable(data, string.Empty);
        }

        public static DataTable ToDataTable<T>(this IEnumerable<T> data, string name)
        {
            var props = TypeDescriptor.GetProperties(typeof(T));
            var table = new DataTable(name);
            for (int i = 0; i < props.Count; i++)
            {
                var prop = props[i];
                table.Columns.Add(prop.Name, prop.PropertyType);
            }
            object[] values = new object[props.Count];
            foreach (T item in data)
            {
                for (int i = 0; i < values.Length; i++)
                {
                    values[i] = props[i].GetValue(item);
                }
                table.Rows.Add(values);
            }
            return table;
        }
    }

    #endregion

    public class ExportTableFactory
    {
        private Configuration configuration;

        public ExportTableFactory(Configuration configuration)
        {
            this.configuration = configuration;
        }
        
        public DataTable GetTable(NotarialServiceDataContext dc, DateRange dateRange)
        {
            var data = GetData(dc, dateRange);                           
            return data.ToDataTable("Импорт бланков НОТАРИУС");
        }

        protected IEnumerable<ExportDTO> GetData(NotarialServiceDataContext dc, DateRange dateRange)
        {
            var result = new List<ExportDTO>();

            //result.AddRange(GetNew(dc, dateRange));
            result.AddRange(GetUsed(dc, dateRange));

            result.AddRange(GetDublicate(dc, dateRange));

            result.AddRange(GetBad(dc, dateRange));
            result.AddRange(GetDefect(dc, dateRange));
            result.AddRange(GetLost(dc, dateRange));
            result.AddRange(GetMissing(dc, dateRange));

            return result;
        }

        protected IEnumerable<ExportDTO> GetNew(NotarialServiceDataContext dc, DateRange dateRange)
        {
            return dc.NotarialFormRange
                        .Where(nr => nr.CreateDate >= dateRange.StartDate && nr.CreateDate <= dateRange.EndDate)
                        .Select(nr => nr.ToNotarialFormEnot(this.configuration))
                        .ToList();
        }

        protected IEnumerable<ExportDTO> GetUsed(NotarialServiceDataContext dc, DateRange dateRange)
        {
            return dc.Orders
                        .Where(o => o.Finished.HasValue
                                    && o.Finished.Value >= dateRange.StartDate && o.Finished.Value <= dateRange.EndDate
                                    && o.NotarialRegister != null
                                    && o.NotarialRegisterRow.HasValue
                                    && o.NotarialForm.Count > 0)
                        .ToList()
                        .Select(o => o.ToNotarialFormEnot(dc, this.configuration))
                        .Where(i => i != null)
                        .ToList();
        }

        #region two step

        protected IEnumerable<ExportDTO> GetDublicate(NotarialServiceDataContext dc, DateRange dateRange)
        {
            var currentDate = DateTime.Now;
            var result = new List<ExportDTO>();
            var forms = dc.NotarialForm.Where(nf => nf.StatusId == (int)NotarialFormStatusType.Dublicate
                                               && !nf.IsInEnot
                                               && nf.StatusChangeDate >= dateRange.StartDate && nf.StatusChangeDate <= dateRange.EndDate);

            foreach (var nf in forms)
            {
                result.Add(new ExportDTO
                {
                    ExternalID = "fdubl" + nf.Name,
                    RecordDeleted = false,
                    ChamberID = this.configuration.ChamberID,
                    NotaryID = this.configuration.NotaryID,
                    OperationDate = nf.StatusChangeDate,
                    OperationType = (short)OperationType.FoundDublicate,
                    Note = "обнаружены дубликаты",
                    Blanks = string.Format("{0},{1},1,7", nf.NotarialFormSerialNumber.Name, nf.Name),
                });

                result.Add(new ExportDTO
                {
                    ExternalID = "rdubl" + nf.Name,
                    RecordDeleted = false,
                    ChamberID = this.configuration.ChamberID,
                    NotaryID = this.configuration.NotaryID,
                    OperationDate = currentDate,
                    OperationType = (short)OperationType.ReturnDublicate,
                    Note = "возврат дубликатов",
                    Blanks = string.Format("{0},{1},1,7", nf.NotarialFormSerialNumber.Name, nf.Name),

                    ActDate = currentDate,
                    ActNumber = "не указан",
                });

                nf.IsInEnot = true;
            }            

            return result;                                        
        }

        protected IEnumerable<ExportDTO> GetBad(NotarialServiceDataContext dc, DateRange dateRange)
        {
            var currentDate = DateTime.Now;
            var result = new List<ExportDTO>();
            var forms = dc.NotarialForm.Where(nf => nf.StatusId == (int)NotarialFormStatusType.Bad
                                               && !nf.IsInEnot
                                               && nf.StatusChangeDate >= dateRange.StartDate && nf.StatusChangeDate <= dateRange.EndDate);

            foreach (var nf in forms)
            {
                result.Add(new ExportDTO
                {
                    ExternalID = "fbad" + nf.Name,
                    RecordDeleted = false,
                    ChamberID = this.configuration.ChamberID,
                    NotaryID = this.configuration.NotaryID,
                    OperationDate = nf.StatusChangeDate,
                    OperationType = (short)OperationType.FoundBad,
                    Note = "обнаружены испорченные",
                    Blanks = string.Format("{0},{1},{1},7", nf.NotarialFormSerialNumber.Name, nf.Name),
                });

                result.Add(new ExportDTO
                {
                    ExternalID = "rbad" + nf.Name,
                    RecordDeleted = false,
                    ChamberID = this.configuration.ChamberID,
                    NotaryID = this.configuration.NotaryID,
                    OperationDate = currentDate,
                    OperationType = (short)OperationType.ReturnBad,
                    Note = "возврат испорченных",
                    Blanks = string.Format("{0},{1},{1},7", nf.NotarialFormSerialNumber.Name, nf.Name),

                    ActDate = currentDate,
                    ActNumber = "не указан",
                });

                nf.IsInEnot = true;
            }

            return result;
        }

        protected IEnumerable<ExportDTO> GetDefect(NotarialServiceDataContext dc, DateRange dateRange)
        {
            var currentDate = DateTime.Now;
            var result = new List<ExportDTO>();            
            var forms = dc.NotarialForm.Where(nf => nf.StatusId == (int)NotarialFormStatusType.Defect
                                               && !nf.IsInEnot
                                               && nf.StatusChangeDate >= dateRange.StartDate && nf.StatusChangeDate <= dateRange.EndDate);

            foreach (var nf in forms)
            {
                result.Add(new ExportDTO
                {
                    ExternalID = "fdefect" + nf.Name,
                    RecordDeleted = false,
                    ChamberID = this.configuration.ChamberID,
                    NotaryID = this.configuration.NotaryID,
                    OperationDate = nf.StatusChangeDate,
                    OperationType = (short)OperationType.FoundDefect,
                    Note = "обранужены бракованные",
                    Blanks = string.Format("{0},{1},{1},7", nf.NotarialFormSerialNumber.Name, nf.Name),
                });

                result.Add(new ExportDTO
                {
                    ExternalID = "rdefect" + nf.Name,
                    RecordDeleted = false,
                    ChamberID = this.configuration.ChamberID,
                    NotaryID = this.configuration.NotaryID,
                    OperationDate = currentDate,
                    OperationType = (short)OperationType.ReturnDefect,
                    Note = "возврат бракованных",
                    Blanks = string.Format("{0},{1},{1},7", nf.NotarialFormSerialNumber.Name, nf.Name),

                    ActDate = currentDate,
                    ActNumber = "не указан",
                });

                nf.IsInEnot = true;
            }

            return result;
        }

        #endregion

        #region one step

        protected IEnumerable<ExportDTO> GetLost(NotarialServiceDataContext dc, DateRange dateRange)
        {
            var result = new List<ExportDTO>();

            var forms = dc.NotarialForm.Where(nf => nf.StatusId == (int)NotarialFormStatusType.Lost 
                                               && !nf.IsInEnot
                                               && nf.StatusChangeDate >= dateRange.StartDate && nf.StatusChangeDate <= dateRange.EndDate);

            foreach (var nf in forms)
            {
                result.Add(new ExportDTO
                {
                    ExternalID = "flost" + nf.Name,
                    RecordDeleted = false,
                    ChamberID = this.configuration.ChamberID,
                    NotaryID = this.configuration.NotaryID,
                    OperationDate = nf.StatusChangeDate,
                    OperationType = (short)OperationType.FoundLost,
                    Note = "обнаружено утрата,хищение",
                    Blanks = string.Format("{0},{1},{1},7", nf.NotarialFormSerialNumber.Name, nf.Name),
                });
                nf.IsInEnot = true;
            }

            return result;
        }

        protected IEnumerable<ExportDTO> GetMissing(NotarialServiceDataContext dc, DateRange dateRange)
        {
            var result = new List<ExportDTO>();

            var forms = dc.NotarialForm.Where(nf => nf.StatusId == (int)NotarialFormStatusType.Missing
                                               && !nf.IsInEnot
                                               && nf.StatusChangeDate >= dateRange.StartDate && nf.StatusChangeDate <= dateRange.EndDate);
            foreach (var nf in forms)
            {
                result.Add(new ExportDTO
                {
                    ExternalID = "fmis" + nf.Name,
                    RecordDeleted = false,
                    ChamberID = this.configuration.ChamberID,
                    NotaryID = this.configuration.NotaryID,
                    OperationDate = nf.StatusChangeDate,
                    OperationType = (short)OperationType.FoundMissing,
                    Note = "обнаружено недовложение",
                    Blanks = string.Format("{0},{1},{1},7", nf.NotarialFormSerialNumber.Name, nf.Name),
                });
                nf.IsInEnot = true;
            }           

            return result;
        }

        #endregion
    }
}
